﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда

#Область СлужебныйПрограммныйИнтерфейс

// Обновляет возможные права для настройки прав объектов и сохраняет состав последних изменений.
//
// Параметры:
//  ЕстьИзменения - Булево - (возвращаемое значение) - если изменения найдены,
//                  устанавливается Истина, иначе не изменяется.
//
Процедура ОбновитьВозможныеПраваДляНастройкиПравОбъектов(ЕстьИзменения = Неопределено) Экспорт
	
	СвойстваСеанса = УправлениеДоступомСлужебныйПовтИсп.ОписаниеСвойствВидовДоступаСеанса().СвойстваСеанса;
	НовоеЗначение = "";
	ПроверенныеВозможныеПраваСеанса(СвойстваСеанса, НовоеЗначение);
	
	НачатьТранзакцию();
	Попытка
		ЕстьТекущиеИзменения = Ложь;
		
		СтандартныеПодсистемыСервер.ОбновитьПараметрРаботыПрограммы(
			"СтандартныеПодсистемы.УправлениеДоступом.ВозможныеПраваДляНастройкиПравОбъектов",
			НовоеЗначение, ЕстьТекущиеИзменения);
		
		СтандартныеПодсистемыСервер.ДобавитьИзмененияПараметраРаботыПрограммы(
			"СтандартныеПодсистемы.УправлениеДоступом.ВозможныеПраваДляНастройкиПравОбъектов",
			?(ЕстьТекущиеИзменения,
			  Новый ФиксированнаяСтруктура("ЕстьИзменения", Истина),
			  Новый ФиксированнаяСтруктура()) );
		
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
	Если ЕстьТекущиеИзменения Тогда
		ЕстьИзменения = Истина;
	КонецЕсли;
	
КонецПроцедуры

// Процедура обновляет вспомогательные данные регистра по результату изменения
// возможных прав по значениям доступа, сохраненных в параметрах ограничения доступа.
//
Процедура ОбновитьВспомогательныеДанныеРегистраПоИзменениямКонфигурации() Экспорт
	
	Кэш = УправлениеДоступомСлужебныйПовтИсп.ОписаниеВозможныхПравСеансаДляНастройкиПравОбъектов();
	НовоеЗначение = Кэш.ХешСумма;
	
	ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ОбновленныеВозможныеПраваДляНастройкиПравОбъектов";
	СтароеЗначение = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина);
	
	Если СтароеЗначение = НовоеЗначение Тогда
		Возврат;
	КонецЕсли;
	
	Блокировка = Новый БлокировкаДанных;
	ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ПараметрыРаботыВерсийРасширений");
	ЭлементБлокировки.УстановитьЗначение("ВерсияРасширений", Справочники.ВерсииРасширений.ПустаяСсылка());
	ЭлементБлокировки.УстановитьЗначение("ИмяПараметра", ИмяПараметра);
	
	НачатьТранзакцию();
	Попытка
		Блокировка.Заблокировать();
		УжеИзменен = Ложь;
		СтароеЗначение = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина, УжеИзменен);
		Если СтароеЗначение <> НовоеЗначение Тогда
			Если УжеИзменен Тогда
				УправлениеДоступомСлужебный.ПроверитьАктуальностьМетаданных();
			КонецЕсли;
			ОбновитьВспомогательныеДанныеРегистра();
			СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, НовоеЗначение, Истина);
		КонецЕсли;
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

// Возвращает настройки прав объекта.
//
// Параметры:
//  СсылкаНаОбъект - ОпределяемыйТип.ВладелецНастроекПрав - ссылка на объект для которого нужно прочитать настройки прав.
//
// Возвращаемое значение:
//  Структура:
//    * Наследовать        - Булево - флажок наследования настроек прав родителей.
//    * Настройки          - ТаблицаЗначений:
//                         ** ВладелецНастройки     - ОпределяемыйТип.ВладелецНастроекПрав - ссылка на объект
//                                                    или родителя объекта (из иерархии родителей объекта).
//                         ** НаследованиеРазрешено - Булево - разрешено наследование.
//                         ** Пользователь          - СправочникСсылка.Пользователи
//                                                  - СправочникСсылка.ГруппыПользователей
//                                                  - СправочникСсылка.ВнешниеПользователи
//                                                  - СправочникСсылка.ГруппыВнешнихПользователей.
//
//                         Имена прав, указанные в переопределяемой 
//                         процедуре ПриЗаполненииВозможныхПравДляНастройкиПравОбъектов:
//                         # <ИмяПрава1>           = Неопределено
//                                                 = Булево -
//                                                       Неопределено - право не настроено,
//                                                       Истина       - право разрешено,
//                                                       Ложь         - право запрещено.
//                         # <ИмяПрава2>           = Неопределено
//                                                 = Булево - аналогично.
//
Функция Прочитать(Знач СсылкаНаОбъект) Экспорт
	
	ВозможныеПрава = УправлениеДоступомСлужебный.ВозможныеПраваДляНастройкиПравОбъектов();
	
	ОписаниеПрав = ВозможныеПрава.ПоТипам.Получить(ТипЗнч(СсылкаНаОбъект));
	
	Если ОписаниеПрав = Неопределено Тогда
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Ошибка в процедуре %1
			           |
			           |Неверное значение параметра %2 ""%3"".
			           |Для объектов таблицы ""%4"" права не настраиваются.'"),
			"РегистрыСведений.НастройкиПравОбъектов.Прочитать",
			"СсылкаНаОбъект",
			Строка(СсылкаНаОбъект),
			СсылкаНаОбъект.Метаданные().ПолноеИмя());
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	НастройкиПрав = Новый Структура;
	
	// Получения значения настройки наследования.
	НастройкиПрав.Вставить("Наследовать",
		РегистрыСведений.НаследованиеНастроекПравОбъектов.НаследованиеНастроек(СсылкаНаОбъект));
	
	// Подготовка структуры таблицы настроек прав.
	Настройки = Новый ТаблицаЗначений;
	Настройки.Колонки.Добавить("Пользователь");
	Настройки.Колонки.Добавить("ВладелецНастройки");
	Настройки.Колонки.Добавить("НаследованиеРазрешено", Новый ОписаниеТипов("Булево"));
	Настройки.Колонки.Добавить("НастройкаРодителя",     Новый ОписаниеТипов("Булево"));
	Для каждого ОписаниеПрава Из ОписаниеПрав Цикл
		Настройки.Колонки.Добавить(ОписаниеПрава.Ключ);
	КонецЦикла;
	
	Если ВозможныеПрава.ИерархическиеТаблицы.Получить(ТипЗнч(СсылкаНаОбъект)) = Неопределено Тогда
		НаследованиеНастроек = УправлениеДоступомСлужебныйПовтИсп.ТаблицаПустогоНабораЗаписей(
			Метаданные.РегистрыСведений.НаследованиеНастроекПравОбъектов.ПолноеИмя()).Получить(); // ТаблицаЗначений
		НоваяСтрока = НаследованиеНастроек.Добавить();
		НаследованиеНастроек.Колонки.Добавить("Уровень", Новый ОписаниеТипов("Число"));
		НоваяСтрока.Объект   = СсылкаНаОбъект;
		НоваяСтрока.Родитель = СсылкаНаОбъект;
	Иначе
		НаследованиеНастроек = РегистрыСведений.НаследованиеНастроекПравОбъектов.РодителиОбъекта(
			СсылкаНаОбъект, , , Ложь);
	КонецЕсли;
	
	// Чтение настроек объекта и родителей от которых наследуются настройки.
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("Объект", СсылкаНаОбъект);
	Запрос.УстановитьПараметр("НаследованиеНастроек", НаследованиеНастроек);
	Запрос.Текст =
	"ВЫБРАТЬ
	|	НаследованиеНастроек.Объект КАК Объект,
	|	НаследованиеНастроек.Родитель КАК Родитель,
	|	НаследованиеНастроек.Уровень КАК Уровень
	|ПОМЕСТИТЬ НаследованиеНастроек
	|ИЗ
	|	&НаследованиеНастроек КАК НаследованиеНастроек
	|
	|ИНДЕКСИРОВАТЬ ПО
	|	НаследованиеНастроек.Объект,
	|	НаследованиеНастроек.Родитель
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	НаследованиеНастроек.Родитель КАК ВладелецНастройки,
	|	НастройкиПравОбъектов.Пользователь КАК Пользователь,
	|	НастройкиПравОбъектов.Право КАК Право,
	|	ВЫБОР
	|		КОГДА НаследованиеНастроек.Родитель <> &Объект
	|			ТОГДА ИСТИНА
	|		ИНАЧЕ ЛОЖЬ
	|	КОНЕЦ КАК НастройкаРодителя,
	|	НастройкиПравОбъектов.ПравоЗапрещено КАК ПравоЗапрещено,
	|	НастройкиПравОбъектов.НаследованиеРазрешено КАК НаследованиеРазрешено
	|ИЗ
	|	РегистрСведений.НастройкиПравОбъектов КАК НастройкиПравОбъектов
	|		ВНУТРЕННЕЕ СОЕДИНЕНИЕ НаследованиеНастроек КАК НаследованиеНастроек
	|		ПО НастройкиПравОбъектов.Объект = НаследованиеНастроек.Родитель
	|ГДЕ
	|	(НаследованиеНастроек.Родитель = &Объект
	|			ИЛИ НастройкиПравОбъектов.НаследованиеРазрешено)
	|
	|УПОРЯДОЧИТЬ ПО
	|	НастройкаРодителя УБЫВ,
	|	НаследованиеНастроек.Уровень,
	|	НастройкиПравОбъектов.ПорядокНастройки";
	Таблица = Запрос.Выполнить().Выгрузить();
	
	ТекущийВладелецНастройки = Неопределено;
	ТекущийПользователь = Неопределено;
	Для каждого Строка Из Таблица Цикл
		Если ТекущийВладелецНастройки <> Строка.ВладелецНастройки
		 ИЛИ ТекущийПользователь <> Строка.Пользователь Тогда
			ТекущийВладелецНастройки = Строка.ВладелецНастройки;
			ТекущийПользователь      = Строка.Пользователь;
			Настройка = Настройки.Добавить();
			Настройка.Пользователь      = Строка.Пользователь;
			Настройка.ВладелецНастройки = Строка.ВладелецНастройки;
			Настройка.НастройкаРодителя = Строка.НастройкаРодителя;
		КонецЕсли;
		Если Настройки.Колонки.Найти(Строка.Право) = Неопределено Тогда
			ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Ошибка в процедуре %1
				           |
				           |Для объектов таблицы ""%2""
				           |право ""%3"" не настраивается, однако оно записано
				           |в регистре сведений %4 для
				           |объекта ""%5"".
				           |
				           |Возможно, обновление информационной базы
				           |не выполнено или выполнено с ошибкой.
				           |Требуется исправить данные регистра.'"),
				"РегистрыСведений.НастройкиПравОбъектов.Прочитать",
				СсылкаНаОбъект.Метаданные().ПолноеИмя(),
				Строка.Право,
				"НастройкиПравОбъектов",
				Строка(СсылкаНаОбъект));
			ВызватьИсключение ТекстОшибки;
		КонецЕсли;
		Настройка.НаследованиеРазрешено = Настройка.НаследованиеРазрешено ИЛИ Строка.НаследованиеРазрешено;
		Настройка[Строка.Право] = НЕ Строка.ПравоЗапрещено;
	КонецЦикла;
	
	НастройкиПрав.Вставить("Настройки", Настройки);
	
	Возврат НастройкиПрав;
	
КонецФункции

// Записывает настройки прав объекта.
//
// Параметры:
//  СсылкаНаОбъект - ОпределяемыйТип.ВладелецНастроекПрав
//  Настройки          - ТаблицаЗначений:
//                         * ВладелецНастройки     - ОпределяемыйТип.ВладелецНастроекПрав - ссылка на объект
//                                                   или родителя объекта (из иерархии родителей объекта).
//                         * НаследованиеРазрешено - Булево - разрешено наследование.
//                         * Пользователь          - СправочникСсылка.Пользователи
//                                                   СправочникСсылка.ГруппыПользователей
//                                                   СправочникСсылка.ВнешниеПользователи
//                                                   СправочникСсылка.ГруппыВнешнихПользователей.
//
//                         Имена прав, указанные в переопределяемой 
//                         процедуре ПриЗаполненииВозможныхПравДляНастройкиПравОбъектов:
//                         # <ИмяПрава1>           = Неопределено
//                                                 = Булево -
//                                                       Неопределено - право не настроено,
//                                                       Истина       - право разрешено,
//                                                       Ложь         - право запрещено.
//                         # <ИмяПрава2>           = Неопределено
//                                                 = Булево - аналогично.
//
//  Наследовать - Булево - флажок наследования настроек прав родителей.
//
Процедура Записать(Знач СсылкаНаОбъект, Знач Настройки, Знач Наследовать) Экспорт
	
	ВозможныеПрава = УправлениеДоступомСлужебный.ВозможныеПраваДляНастройкиПравОбъектов();
	ОписаниеПрав = ВозможныеПрава.ПоТипамСсылок.Получить(ТипЗнч(СсылкаНаОбъект)); // Массив из см. СвойстваВозможногоПрава
	
	Если ОписаниеПрав = Неопределено Тогда
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Ошибка в процедуре %1
			           |
			           |Неверное значение параметра %2 ""%3"".
			           |Для объектов таблицы ""%4"" права не настраиваются.'"),
			"РегистрыСведений.НастройкиПравОбъектов.Прочитать",
			"СсылкаНаОбъект",
			Строка(СсылкаНаОбъект),
			СсылкаНаОбъект.Метаданные().ПолноеИмя());
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	НачатьТранзакцию();
	Попытка
		Блокировка = Новый БлокировкаДанных;
		ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.НаследованиеНастроекПравОбъектов");
		ЭлементБлокировки.УстановитьЗначение("Объект", СсылкаНаОбъект);
		ЭлементБлокировки.УстановитьЗначение("Родитель", СсылкаНаОбъект);
		Блокировка.Заблокировать();
		
		// Установка значения настройки наследования.
		НаборЗаписей = РегистрыСведений.НаследованиеНастроекПравОбъектов.СоздатьНаборЗаписей();
		НаборЗаписей.Отбор.Объект.Установить(СсылкаНаОбъект);
		НаборЗаписей.Отбор.Родитель.Установить(СсылкаНаОбъект);
		НаборЗаписей.Прочитать();
		
		Если НаборЗаписей.Количество() = 0 Тогда
			НаследованиеИзменено = Истина;
			НоваяЗапись = НаборЗаписей.Добавить();
			НоваяЗапись.Объект      = СсылкаНаОбъект;
			НоваяЗапись.Родитель    = СсылкаНаОбъект;
			НоваяЗапись.Наследовать = Наследовать;
		Иначе
			НаследованиеИзменено = НаборЗаписей[0].Наследовать <> Наследовать;
			НаборЗаписей[0].Наследовать = Наследовать;
		КонецЕсли;
		
		// Подготовка новых настроек
		НовыеНастройкиПрав = УправлениеДоступомСлужебныйПовтИсп.ТаблицаПустогоНабораЗаписей(
			Метаданные.РегистрыСведений.НастройкиПравОбъектов.ПолноеИмя()).Получить();
		
		ТаблицаОбщихПрав = Справочники.ИдентификаторыОбъектовМетаданных.ПустаяСсылка();
		
		Отбор = Новый Структура("ВладелецНастройки", СсылкаНаОбъект);
		ПорядокНастройки = 0;
		Для каждого Настройка Из Настройки.НайтиСтроки(Отбор) Цикл
			Для каждого ОписаниеПрава Из ОписаниеПрав Цикл
				Если ТипЗнч(Настройка[ОписаниеПрава.Имя]) <> Тип("Булево") Тогда
					Продолжить;
				КонецЕсли;
				ПорядокНастройки = ПорядокНастройки + 1;
				
				НастройкаПрав = НовыеНастройкиПрав.Добавить();
				НастройкаПрав.ПорядокНастройки      = ПорядокНастройки;
				НастройкаПрав.Объект                = СсылкаНаОбъект;
				НастройкаПрав.Пользователь          = Настройка.Пользователь;
				НастройкаПрав.Право                 = ОписаниеПрава.Имя;
				НастройкаПрав.Таблица               = ТаблицаОбщихПрав;
				НастройкаПрав.ПравоЗапрещено        = НЕ Настройка[ОписаниеПрава.Имя];
				НастройкаПрав.НаследованиеРазрешено = Настройка.НаследованиеРазрешено;
				// Кэш-реквизиты
				НастройкаПрав.УровеньРазрешенияПрава =
					?(НастройкаПрав.ПравоЗапрещено, 0, ?(НастройкаПрав.НаследованиеРазрешено, 2, 1));
				НастройкаПрав.УровеньЗапрещенияПрава =
					?(НастройкаПрав.ПравоЗапрещено, ?(НастройкаПрав.НаследованиеРазрешено, 2, 1), 0);
				
				ДобавленыНастройкиОтдельныхТаблиц = Ложь;
				Для каждого КлючИЗначение Из ВозможныеПрава.ОтдельныеТаблицы Цикл
					ОтдельнаяТаблица = КлючИЗначение.Ключ;
					ЧтениеТаблицы    = ОписаниеПрава.ЧтениеВТаблицах.Найти(   ОтдельнаяТаблица) <> Неопределено;
					ИзменениеТаблицы = ОписаниеПрава.ИзменениеВТаблицах.Найти(ОтдельнаяТаблица) <> Неопределено;
					Если НЕ ЧтениеТаблицы И НЕ ИзменениеТаблицы Тогда
						Продолжить;
					КонецЕсли;
					ДобавленыНастройкиОтдельныхТаблиц = Истина;
					НастройкаПравТаблицы = НовыеНастройкиПрав.Добавить();
					ЗаполнитьЗначенияСвойств(НастройкаПравТаблицы, НастройкаПрав);
					НастройкаПравТаблицы.Таблица = ОтдельнаяТаблица;
					Если ЧтениеТаблицы Тогда
						НастройкаПравТаблицы.УровеньРазрешенияЧтения = НастройкаПрав.УровеньРазрешенияПрава;
						НастройкаПравТаблицы.УровеньЗапрещенияЧтения = НастройкаПрав.УровеньЗапрещенияПрава;
					КонецЕсли;
					Если ИзменениеТаблицы Тогда
						НастройкаПравТаблицы.УровеньРазрешенияИзменения = НастройкаПрав.УровеньРазрешенияПрава;
						НастройкаПравТаблицы.УровеньЗапрещенияИзменения = НастройкаПрав.УровеньЗапрещенияПрава;
					КонецЕсли;
				КонецЦикла;
				
				ОбщееЧтение    = ОписаниеПрава.ЧтениеВТаблицах.Найти(   ТаблицаОбщихПрав) <> Неопределено;
				ОбщееИзменение = ОписаниеПрава.ИзменениеВТаблицах.Найти(ТаблицаОбщихПрав) <> Неопределено;
				
				Если НЕ ОбщееЧтение И НЕ ОбщееИзменение И ДобавленыНастройкиОтдельныхТаблиц Тогда
					НовыеНастройкиПрав.Удалить(НастройкаПрав);
				Иначе
					Если ОбщееЧтение Тогда
						НастройкаПрав.УровеньРазрешенияЧтения = НастройкаПрав.УровеньРазрешенияПрава;
						НастройкаПрав.УровеньЗапрещенияЧтения = НастройкаПрав.УровеньЗапрещенияПрава;
					КонецЕсли;
					Если ОбщееИзменение Тогда
						НастройкаПрав.УровеньРазрешенияИзменения = НастройкаПрав.УровеньРазрешенияПрава;
						НастройкаПрав.УровеньЗапрещенияИзменения = НастройкаПрав.УровеньЗапрещенияПрава;
					КонецЕсли;
				КонецЕсли;
			КонецЦикла;
		КонецЦикла;
	
		// Запись настроек прав объекта и значения наследования настроек прав.
		Данные = Новый Структура;
		Данные.Вставить("НаборЗаписей",   РегистрыСведений.НастройкиПравОбъектов);
		Данные.Вставить("НовыеЗаписи",    НовыеНастройкиПрав);
		Данные.Вставить("ПолеОтбора",     "Объект");
		Данные.Вставить("ЗначениеОтбора", СсылкаНаОбъект);
		
		ЕстьИзменения = Ложь;
		УправлениеДоступомСлужебный.ОбновитьНаборЗаписей(Данные, ЕстьИзменения);
		
		Если ЕстьИзменения Тогда
			ОбъектыСИзменениями = Новый Массив;
		Иначе
			ОбъектыСИзменениями = Неопределено;
		КонецЕсли;
		
		Если НаследованиеИзменено Тогда
			НаборЗаписей.Записать();
			РегистрыСведений.НаследованиеНастроекПравОбъектов.ОбновитьРодителейВладельца(
				СсылкаНаОбъект, , Истина, ОбъектыСИзменениями);
		КонецЕсли;
		
		Если ОбъектыСИзменениями <> Неопределено Тогда
			ДобавитьОбъектыИерархии(СсылкаНаОбъект, ОбъектыСИзменениями);
		КонецЕсли;
		
		Если (ЕстьИзменения Или НаследованиеИзменено)
		   И УправлениеДоступомСлужебный.ОграничиватьДоступНаУровнеЗаписейУниверсально() Тогда
			
			ПараметрыПланирования = УправлениеДоступомСлужебный.ПараметрыПланированияОбновленияДоступа();
			ПараметрыПланирования.КлючиДоступаКДанным = Ложь;
			ПараметрыПланирования.Описание = "НастройкиПравОбъектовЗаписать";
			
			ПолноеИмя = СсылкаНаОбъект.Метаданные().ПолноеИмя();
			УправлениеДоступомСлужебный.ЗапланироватьОбновлениеДоступа(ПолноеИмя, ПараметрыПланирования);
		КонецЕсли;
		
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

// Процедура обновляет вспомогательные данные регистра при изменении конфигурации.
//
// Параметры:
//  ЕстьИзменения - Булево - (возвращаемое значение) - если производилась запись,
//                  устанавливается Истина, иначе не изменяется.
//
Процедура ОбновитьВспомогательныеДанныеРегистра(ЕстьИзменения = Неопределено) Экспорт
	
	УстановитьПривилегированныйРежим(Истина);
	
	ВозможныеПрава = УправлениеДоступомСлужебный.ВозможныеПраваДляНастройкиПравОбъектов();
	
	ТаблицыПрав = Новый ТаблицаЗначений;
	ТаблицыПрав.Колонки.Добавить("ВладелецПрав", Метаданные.РегистрыСведений.НастройкиПравОбъектов.Измерения.Объект.Тип);
	ТаблицыПрав.Колонки.Добавить("Право",        Метаданные.РегистрыСведений.НастройкиПравОбъектов.Измерения.Право.Тип);
	ТаблицыПрав.Колонки.Добавить("Таблица",      Метаданные.РегистрыСведений.НастройкиПравОбъектов.Измерения.Таблица.Тип);
	ТаблицыПрав.Колонки.Добавить("Чтение",       Новый ОписаниеТипов("Булево"));
	ТаблицыПрав.Колонки.Добавить("Изменение",    Новый ОписаниеТипов("Булево"));
	
	ПустыеСсылкиВладелецПрав = УправлениеДоступомСлужебныйПовтИсп.СоответствиеПустыхСсылокУказаннымТипамСсылок(
		"РегистрСведений.НастройкиПравОбъектов.Измерение.Объект");
	
	Отбор = Новый Структура;
	Для каждого КлючИЗначение Из ВозможныеПрава.ПоТипамСсылок Цикл
		ТипВладельцаПрав = КлючИЗначение.Ключ;
		ОписаниеПрав     = КлючИЗначение.Значение; // ФиксированныйМассив из см. СвойстваВозможногоПрава
		
		Если ПустыеСсылкиВладелецПрав.Получить(ТипВладельцаПрав) = Неопределено Тогда
			ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Ошибка в процедуре %1
				           |модуля менеджера регистра сведений %2.
				           |
				           |Тип владельцев прав ""%3"" не указан в измерении %4.'"),
				"ОбновитьВспомогательныеДанныеРегистра",
				"НастройкиПравОбъектов",
				ТипВладельцаПрав,
				"Объект");
			ВызватьИсключение ТекстОшибки;
		КонецЕсли;
		
		Отбор.Вставить("ВладелецПрав", ПустыеСсылкиВладелецПрав.Получить(ТипВладельцаПрав));
		Для каждого ОписаниеПрава Из ОписаниеПрав Цикл
			Отбор.Вставить("Право", ОписаниеПрава.Имя);
			
			Для каждого Таблица Из ОписаниеПрава.ЧтениеВТаблицах Цикл
				Строка = ТаблицыПрав.Добавить();
				ЗаполнитьЗначенияСвойств(Строка, Отбор);
				Строка.Таблица = Таблица;
				Строка.Чтение = Истина;
			КонецЦикла;
			
			Для каждого Таблица Из ОписаниеПрава.ИзменениеВТаблицах Цикл
				Отбор.Вставить("Таблица", Таблица);
				Строки = ТаблицыПрав.НайтиСтроки(Отбор);
				Если Строки.Количество() = 0 Тогда
					Строка = ТаблицыПрав.Добавить();
					ЗаполнитьЗначенияСвойств(Строка, Отбор);
				Иначе
					Строка = Строки[0];
				КонецЕсли;
				Строка.Изменение = Истина;
			КонецЦикла;
		КонецЦикла;
	КонецЦикла;
	
	ТекстЗапросовВременныхТаблиц =
	"ВЫБРАТЬ
	|	ТаблицыПрав.ВладелецПрав,
	|	ТаблицыПрав.Право,
	|	ТаблицыПрав.Таблица,
	|	ТаблицыПрав.Чтение,
	|	ТаблицыПрав.Изменение
	|ПОМЕСТИТЬ ТаблицыПрав
	|ИЗ
	|	&ТаблицыПрав КАК ТаблицыПрав
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	НастройкиПрав.Объект КАК Объект,
	|	НастройкиПрав.Пользователь КАК Пользователь,
	|	НастройкиПрав.Право КАК Право,
	|	МАКСИМУМ(НастройкиПрав.ПравоЗапрещено) КАК ПравоЗапрещено,
	|	МАКСИМУМ(НастройкиПрав.НаследованиеРазрешено) КАК НаследованиеРазрешено,
	|	МАКСИМУМ(НастройкиПрав.ПорядокНастройки) КАК ПорядокНастройки
	|ПОМЕСТИТЬ НастройкиПрав
	|ИЗ
	|	РегистрСведений.НастройкиПравОбъектов КАК НастройкиПрав
	|
	|СГРУППИРОВАТЬ ПО
	|	НастройкиПрав.Объект,
	|	НастройкиПрав.Пользователь,
	|	НастройкиПрав.Право
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|ВЫБРАТЬ
	|	НастройкиПрав.Объект,
	|	НастройкиПрав.Пользователь,
	|	НастройкиПрав.Право,
	|	ЕСТЬNULL(ТаблицыПрав.Таблица, ЗНАЧЕНИЕ(Справочник.ИдентификаторыОбъектовМетаданных.ПустаяСсылка)) КАК Таблица,
	|	НастройкиПрав.ПравоЗапрещено,
	|	НастройкиПрав.НаследованиеРазрешено,
	|	НастройкиПрав.ПорядокНастройки,
	|	ВЫБОР
	|		КОГДА НастройкиПрав.ПравоЗапрещено
	|			ТОГДА 0
	|		КОГДА НастройкиПрав.НаследованиеРазрешено
	|			ТОГДА 2
	|		ИНАЧЕ 1
	|	КОНЕЦ КАК УровеньРазрешенияПрава,
	|	ВЫБОР
	|		КОГДА НЕ НастройкиПрав.ПравоЗапрещено
	|			ТОГДА 0
	|		КОГДА НастройкиПрав.НаследованиеРазрешено
	|			ТОГДА 2
	|		ИНАЧЕ 1
	|	КОНЕЦ КАК УровеньЗапрещенияПрава,
	|	ВЫБОР
	|		КОГДА НЕ ЕСТЬNULL(ТаблицыПрав.Чтение, ЛОЖЬ)
	|			ТОГДА 0
	|		КОГДА НастройкиПрав.ПравоЗапрещено
	|			ТОГДА 0
	|		КОГДА НастройкиПрав.НаследованиеРазрешено
	|			ТОГДА 2
	|		ИНАЧЕ 1
	|	КОНЕЦ КАК УровеньРазрешенияЧтения,
	|	ВЫБОР
	|		КОГДА НЕ ЕСТЬNULL(ТаблицыПрав.Чтение, ЛОЖЬ)
	|			ТОГДА 0
	|		КОГДА НЕ НастройкиПрав.ПравоЗапрещено
	|			ТОГДА 0
	|		КОГДА НастройкиПрав.НаследованиеРазрешено
	|			ТОГДА 2
	|		ИНАЧЕ 1
	|	КОНЕЦ КАК УровеньЗапрещенияЧтения,
	|	ВЫБОР
	|		КОГДА НЕ ЕСТЬNULL(ТаблицыПрав.Изменение, ЛОЖЬ)
	|			ТОГДА 0
	|		КОГДА НастройкиПрав.ПравоЗапрещено
	|			ТОГДА 0
	|		КОГДА НастройкиПрав.НаследованиеРазрешено
	|			ТОГДА 2
	|		ИНАЧЕ 1
	|	КОНЕЦ КАК УровеньРазрешенияИзменения,
	|	ВЫБОР
	|		КОГДА НЕ ЕСТЬNULL(ТаблицыПрав.Изменение, ЛОЖЬ)
	|			ТОГДА 0
	|		КОГДА НЕ НастройкиПрав.ПравоЗапрещено
	|			ТОГДА 0
	|		КОГДА НастройкиПрав.НаследованиеРазрешено
	|			ТОГДА 2
	|		ИНАЧЕ 1
	|	КОНЕЦ КАК УровеньЗапрещенияИзменения
	|ПОМЕСТИТЬ НовыеДанные
	|ИЗ
	|	НастройкиПрав КАК НастройкиПрав
	|		ЛЕВОЕ СОЕДИНЕНИЕ ТаблицыПрав КАК ТаблицыПрав
	|		ПО (ТИПЗНАЧЕНИЯ(НастройкиПрав.Объект) = ТИПЗНАЧЕНИЯ(ТаблицыПрав.ВладелецПрав))
	|			И НастройкиПрав.Право = ТаблицыПрав.Право
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|УНИЧТОЖИТЬ ТаблицыПрав
	|;
	|
	|////////////////////////////////////////////////////////////////////////////////
	|УНИЧТОЖИТЬ НастройкиПрав";
	
	ТекстЗапроса =
	"ВЫБРАТЬ
	|	НовыеДанные.Объект,
	|	НовыеДанные.Пользователь,
	|	НовыеДанные.Право,
	|	НовыеДанные.Таблица,
	|	НовыеДанные.ПравоЗапрещено,
	|	НовыеДанные.НаследованиеРазрешено,
	|	НовыеДанные.ПорядокНастройки,
	|	НовыеДанные.УровеньРазрешенияПрава,
	|	НовыеДанные.УровеньЗапрещенияПрава,
	|	НовыеДанные.УровеньРазрешенияЧтения,
	|	НовыеДанные.УровеньЗапрещенияЧтения,
	|	НовыеДанные.УровеньРазрешенияИзменения,
	|	НовыеДанные.УровеньЗапрещенияИзменения,
	|	&ПодстановкаПоляВидИзмененияСтроки
	|ИЗ
	|	НовыеДанные КАК НовыеДанные";
	
	// Подготовка выбираемых полей с необязательным отбором.
	Поля = Новый Массив;
	Поля.Добавить(Новый Структура("Объект"));
	Поля.Добавить(Новый Структура("Пользователь"));
	Поля.Добавить(Новый Структура("Право"));
	Поля.Добавить(Новый Структура("Таблица"));
	Поля.Добавить(Новый Структура("ПравоЗапрещено"));
	Поля.Добавить(Новый Структура("НаследованиеРазрешено"));
	Поля.Добавить(Новый Структура("ПорядокНастройки"));
	Поля.Добавить(Новый Структура("УровеньРазрешенияПрава"));
	Поля.Добавить(Новый Структура("УровеньЗапрещенияПрава"));
	Поля.Добавить(Новый Структура("УровеньРазрешенияЧтения"));
	Поля.Добавить(Новый Структура("УровеньЗапрещенияЧтения"));
	Поля.Добавить(Новый Структура("УровеньРазрешенияИзменения"));
	Поля.Добавить(Новый Структура("УровеньЗапрещенияИзменения"));
	
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("ТаблицыПрав", ТаблицыПрав);
	
	Запрос.Текст = УправлениеДоступомСлужебный.ТекстЗапросаВыбораИзменений(
		ТекстЗапроса, Поля, "РегистрСведений.НастройкиПравОбъектов", ТекстЗапросовВременныхТаблиц);
	
	Блокировка = Новый БлокировкаДанных;
	Блокировка.Добавить("РегистрСведений.НастройкиПравОбъектов");
	
	НачатьТранзакцию();
	Попытка
		Блокировка.Заблокировать();
		
		Данные = Новый Структура;
		Данные.Вставить("МенеджерРегистра",      РегистрыСведений.НастройкиПравОбъектов);
		Данные.Вставить("ИзмененияСоставаСтрок", Запрос.Выполнить().Выгрузить());
		
		УправлениеДоступомСлужебный.ОбновитьРегистрСведений(Данные, ЕстьИзменения);
		
		ЗафиксироватьТранзакцию();
	Исключение
		ОтменитьТранзакцию();
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

// Только для вызова из УправлениеДоступомСлужебный.ВозможныеПраваДляНастройкиПравОбъектов.
// Смотри также ПроверенныеВозможныеПраваСеанса.
//
// Возвращаемое значение:
//   см. УправлениеДоступомСлужебный.ВозможныеПраваДляНастройкиПравОбъектов
//
Функция ВозможныеПраваДляНастройкиПравОбъектов() Экспорт
	
	Кэш = УправлениеДоступомСлужебныйПовтИсп.ОписаниеВозможныхПравСеансаДляНастройкиПравОбъектов();
	
	ТекущаяДатаСеанса = ТекущаяДатаСеанса();
	Если Кэш.Проверка.Дата + 3 > ТекущаяДатаСеанса Тогда
		Возврат Кэш.ВозможныеПраваСеанса;
	КонецЕсли;
	
	НовоеЗначение = Кэш.ХешСумма;
	
	ИмяПараметра = "СтандартныеПодсистемы.УправлениеДоступом.ВозможныеПраваДляНастройкиПравОбъектов";
	СтароеЗначение = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина);
	
	Если СтароеЗначение <> НовоеЗначение Тогда
		Блокировка = Новый БлокировкаДанных;
		ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ПараметрыРаботыВерсийРасширений");
		ЭлементБлокировки.УстановитьЗначение("ВерсияРасширений", Справочники.ВерсииРасширений.ПустаяСсылка());
		ЭлементБлокировки.УстановитьЗначение("ИмяПараметра", ИмяПараметра);
		НачатьТранзакцию();
		Попытка
			Блокировка.Заблокировать();
			УжеИзменен = Ложь;
			СтароеЗначение = СтандартныеПодсистемыСервер.ПараметрРаботыРасширения(ИмяПараметра, Истина, УжеИзменен);
			Если СтароеЗначение <> НовоеЗначение Тогда
				Если УжеИзменен Тогда
					УправлениеДоступомСлужебный.ПроверитьАктуальностьМетаданных();
				КонецЕсли;
				УстановитьОтключениеБезопасногоРежима(Истина);
				УстановитьПривилегированныйРежим(Истина);
				СтандартныеПодсистемыСервер.УстановитьПараметрРаботыРасширения(ИмяПараметра, НовоеЗначение, Истина);
				УстановитьПривилегированныйРежим(Ложь);
				УстановитьОтключениеБезопасногоРежима(Ложь);
			КонецЕсли;
			ЗафиксироватьТранзакцию();
		Исключение
			ОтменитьТранзакцию();
			ВызватьИсключение;
		КонецПопытки;
	КонецЕсли;
	
	Кэш.Проверка.Дата = ТекущаяДатаСеанса;
	
	Возврат Кэш.ВозможныеПраваСеанса;
	
КонецФункции

////////////////////////////////////////////////////////////////////////////////
// Обновление информационной базы.

Процедура ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию(Параметры) Экспорт
	
	// Регистрация данных не требуется.
	Возврат;
	
КонецПроцедуры

Процедура ОбработатьДанныеДляПереходаНаНовуюВерсию(Параметры) Экспорт
	
	ОбновитьВспомогательныеДанныеРегистра();
	
	Параметры.ОбработкаЗавершена = Истина;
	
КонецПроцедуры

////////////////////////////////////////////////////////////////////////////////
// Вспомогательные процедуры и функции.

Процедура ДобавитьОбъектыИерархии(Ссылка, МассивОбъектов)
	
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("Ссылка", Ссылка);
	Запрос.УстановитьПараметр("МассивОбъектов", МассивОбъектов);
	
	Запрос.Текст = СтрЗаменить(
	"ВЫБРАТЬ
	|	ТаблицаСИерархией.Ссылка
	|ИЗ
	|	ТаблицаОбъектов КАК ТаблицаСИерархией
	|ГДЕ
	|	ТаблицаСИерархией.Ссылка В ИЕРАРХИИ(&Ссылка)
	|	И НЕ ТаблицаСИерархией.Ссылка В (&МассивОбъектов)",
	"ТаблицаОбъектов",
	Ссылка.Метаданные().ПолноеИмя());
	
	Выборка = Запрос.Выполнить().Выбрать();
	
	Пока Выборка.Следующий() Цикл
		МассивОбъектов.Добавить(Выборка.Ссылка);
	КонецЦикла;
	
КонецПроцедуры

// Возвращаемое значение:
//   см. УправлениеДоступомПереопределяемый.ПриЗаполненииВозможныхПравДляНастройкиПравОбъектов.ВозможныеПрава
//
Функция ЗаполненныеВозможныеПраваСеанса()
	
	ВозможныеПрава = Новый ТаблицаЗначений();
	ВозможныеПрава.Колонки.Добавить("ВладелецПрав",        Новый ОписаниеТипов("Строка"));
	ВозможныеПрава.Колонки.Добавить("Имя",                 Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(60)));
	ВозможныеПрава.Колонки.Добавить("Заголовок",           Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(60)));
	ВозможныеПрава.Колонки.Добавить("Подсказка",           Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(150)));
	ВозможныеПрава.Колонки.Добавить("НачальноеЗначение",   Новый ОписаниеТипов("Булево,Число"));
	ВозможныеПрава.Колонки.Добавить("ТребуемыеПрава",      Новый ОписаниеТипов("Массив"));
	ВозможныеПрава.Колонки.Добавить("ЧтениеВТаблицах",     Новый ОписаниеТипов("Массив"));
	ВозможныеПрава.Колонки.Добавить("ИзменениеВТаблицах",  Новый ОписаниеТипов("Массив"));
	
	ИнтеграцияПодсистемБСП.ПриЗаполненииВозможныхПравДляНастройкиПравОбъектов(ВозможныеПрава);
	УправлениеДоступомПереопределяемый.ПриЗаполненииВозможныхПравДляНастройкиПравОбъектов(ВозможныеПрава);
	
	Возврат ВозможныеПрава;
	
КонецФункции

// Для процедуры УправлениеДоступомСлужебныйПовтИсп.ОписаниеВозможныхПравСеансаДляНастройкиПравОбъектов.
// Смотри также УправлениеДоступомПереопределяемый.ПриЗаполненииВозможныхПравДляНастройкиПравОбъектов.
//
// Параметры:
//  СвойстваВидовДоступа - см. УправлениеДоступомСлужебный.СвойстваВидовДоступа
//                       - Неопределено
//  ХешСумма - Строка - возвращаемое значение.
//
// Возвращаемое значение:
//   см. УправлениеДоступомСлужебный.ВозможныеПраваДляНастройкиПравОбъектов
//
Функция ПроверенныеВозможныеПраваСеанса(СвойстваВидовДоступа = Неопределено, ХешСумма = "") Экспорт
	
	ВозможныеПрава = ЗаполненныеВозможныеПраваСеанса();
	
	ЗаголовокОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		НСтр("ru = 'Ошибка в процедуре %1
		           |общего модуля %2.'"),
		"ПриЗаполненииВозможныхПравДляНастройкиПравОбъектов",
		"УправлениеДоступомПереопределяемый")
		+ Символы.ПС
		+ Символы.ПС;
	
	СвойстваВладельцев   = Новый Соответствие;
	ТипыВладельцев       = Новый СписокЗначений;
	ОтдельныеТаблицы     = Новый Соответствие;
	ИерархическиеТаблицы = Новый Соответствие;
	
	ОпределяемыйТипВладельцевПрав  = УправлениеДоступомСлужебныйПовтИсп.ТипыПоляТаблицы("ОпределяемыйТип.ВладелецНастроекПрав");
	ОпределяемыйТипЗначенийДоступа = УправлениеДоступомСлужебныйПовтИсп.ТипыПоляТаблицы("ОпределяемыйТип.ЗначениеДоступа");
	
	Если СвойстваВидовДоступа = Неопределено Тогда
		СвойстваВидовДоступа = УправлениеДоступомСлужебный.СвойстваВидовДоступа();
	КонецЕсли;
	
	ТипыПодпискиОбновитьГруппыВладельцевНастроекПрав = УправлениеДоступомСлужебныйПовтИсп.ТипыПоляТаблицы(
		"ОпределяемыйТип.ВладелецНастроекПравОбъект");
	
	ТипыПодпискиЗаписатьНаборыЗначенийДоступа = УправлениеДоступомСлужебныйПовтИсп.ТипыОбъектовВПодпискахНаСобытия(
		"ЗаписатьНаборыЗначенийДоступа");
	
	ТипыПодпискиЗаписатьЗависимыеНаборыЗначенийДоступа = УправлениеДоступомСлужебныйПовтИсп.ТипыОбъектовВПодпискахНаСобытия(
		"ЗаписатьЗависимыеНаборыЗначенийДоступа");
	
	ДополнительныеПараметры = Новый Структура;
	ДополнительныеПараметры.Вставить("ВладелецПрав");
	ДополнительныеПараметры.Вставить("ОбщиеПраваВладельцев", Новый Соответствие);
	ДополнительныеПараметры.Вставить("ОтдельныеПраваВладельцев", Новый Соответствие);
	
	ИндексыПравВладельцев = Новый Соответствие;
	
	Для Каждого ВозможноеПраво Из ВозможныеПрава Цикл
		ОбъектМетаданныхВладельца = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ВозможноеПраво.ВладелецПрав);
		
		Если ОбъектМетаданныхВладельца = Неопределено Тогда
			ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не найден владелец прав ""%1"".'"),
				ВозможноеПраво.ВладелецПрав);
			ВызватьИсключение ТекстОшибки;
		КонецЕсли;
		
		ДополнительныеПараметры.ВладелецПрав = ВозможноеПраво.ВладелецПрав;
		
		ЗаполнитьИдентификаторы("ЧтениеВТаблицах",    ВозможноеПраво, ЗаголовокОшибки, ОтдельныеТаблицы, ДополнительныеПараметры);
		ЗаполнитьИдентификаторы("ИзменениеВТаблицах", ВозможноеПраво, ЗаголовокОшибки, ОтдельныеТаблицы, ДополнительныеПараметры);
		
		СвойстваВладельца = СвойстваВладельцев[ВозможноеПраво.ВладелецПрав];
		Если СвойстваВладельца <> Неопределено Тогда
			ПраваВладельца = СвойстваВладельца.ПраваВладельца;
		Иначе
			ПраваВладельца = ПраваВладельца();
			МассивПравВладельца = Новый Массив;
			
			ТипСсылки = СтандартныеПодсистемыСервер.ТипСсылкиИлиКлючаЗаписиОбъектаМетаданных(
				ОбъектМетаданныхВладельца);
			
			ТипОбъекта = СтандартныеПодсистемыСервер.ТипОбъектаИлиНабораЗаписейОбъектаМетаданных(
				ОбъектМетаданныхВладельца);
			
			Если ОпределяемыйТипВладельцевПрав.Получить(ТипСсылки) = Неопределено Тогда
				ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Тип владельца прав ""%1""
					           |не указан в определяемом типе %2.'"),
					Строка(ТипСсылки),
					"ВладелецНастроекПрав");
				ВызватьИсключение ТекстОшибки;
			КонецЕсли;
			
			Если ОпределяемыйТипЗначенийДоступа.Получить(ТипСсылки) = Неопределено Тогда
				Если ТипыПодпискиЗаписатьНаборыЗначенийДоступа = Неопределено Тогда
					ТипыПодпискиЗаписатьНаборыЗначенийДоступа = УправлениеДоступомСлужебныйПовтИсп.ТипыОбъектовВПодпискахНаСобытия(
						"ЗаписатьНаборыЗначенийДоступа");
					ТипыПодпискиЗаписатьЗависимыеНаборыЗначенийДоступа = УправлениеДоступомСлужебныйПовтИсп.ТипыОбъектовВПодпискахНаСобытия(
						"ЗаписатьЗависимыеНаборыЗначенийДоступа");
				КонецЕсли;
				Если ТипыПодпискиЗаписатьЗависимыеНаборыЗначенийДоступа.Получить(ТипОбъекта) <> Неопределено
				 Или ТипыПодпискиЗаписатьНаборыЗначенийДоступа.Получить(ТипОбъекта) <> Неопределено Тогда
				
					ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
						НСтр("ru = 'Тип владельца прав ""%1""
						           |не указан в определяемом типе %2,
						           |но используется для заполнения наборов значений доступа,
						           |т.к. указан в одной из подписок на событие:
						           |- %3,
						           |- %4.
						           |Требуется указать тип в определяемом типе %5
						           |для корректного заполнения регистра %6.'"),
						Строка(ТипСсылки),
						"ЗначениеДоступа",
						"ЗаписатьЗависимыеНаборыЗначенийДоступа" + "*",
						"ЗаписатьНаборыЗначенийДоступа" + "*",
						"ЗначениеДоступа",
						"НаборыЗначенийДоступа");
					ВызватьИсключение ТекстОшибки;
				КонецЕсли;
			КонецЕсли;
			
			СвойстваВидаДоступа = СвойстваВидовДоступа.ПоТипамЗначений.Получить(ТипСсылки); // см. УправлениеДоступомСлужебный.СвойстваВидаДоступа
			Если СвойстваВидаДоступа <> Неопределено Тогда
				ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Тип владельца прав ""%1""
					           |не может использоваться, как тип значений доступа,
					           |но обнаружен в описании вида доступа ""%2"".'"),
					Строка(ТипСсылки),
					СвойстваВидаДоступа.Имя);
				ВызватьИсключение ТекстОшибки;
			КонецЕсли;
			
			Если СвойстваВидовДоступа.ПоТипамГруппИЗначений.Получить(ТипСсылки) <> Неопределено Тогда
				ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Тип владельца прав ""%1""
					           |не может использоваться, как тип групп значений доступа,
					           |но обнаружен в описании вида доступа ""%2"".'"),
					Строка(ТипСсылки),
					СвойстваВидаДоступа.Имя);
				ВызватьИсключение ТекстОшибки;
			КонецЕсли;
			
			Если ТипыПодпискиОбновитьГруппыВладельцевНастроекПрав.Получить(ТипОбъекта) = Неопределено Тогда
				ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Тип владельца прав ""%1""
					           |не указан в определяемом типе %2.'"),
					Строка(ТипОбъекта), "ВладелецНастроекПравОбъект");
				ВызватьИсключение ТекстОшибки;
			КонецЕсли;
			
			СвойстваВладельца = Новый Структура;
			СвойстваВладельца.Вставить("ПраваВладельца", ПраваВладельца);
			СвойстваВладельца.Вставить("МассивПравВладельца", МассивПравВладельца);
			СвойстваВладельца.Вставить("ТипСсылки", ТипСсылки);
			СвойстваВладельца.Вставить("ТипОбъекта", ТипОбъекта);
			СвойстваВладельцев.Вставить(ВозможноеПраво.ВладелецПрав, СвойстваВладельца);
			
			Если ИерархическийОбъектМетаданных(ОбъектМетаданныхВладельца) Тогда
				ИерархическиеТаблицы.Вставить(ТипСсылки,  Истина);
				ИерархическиеТаблицы.Вставить(ТипОбъекта, Истина);
			КонецЕсли;
			
			ТипыВладельцев.Добавить(ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(
				ВозможноеПраво.ВладелецПрав).ПустаяСсылка(), ВозможноеПраво.ВладелецПрав);
				
			ИндексыПравВладельцев.Вставить(ВозможноеПраво.ВладелецПрав, 0);
		КонецЕсли;
		
		Если ПраваВладельца.Получить(ВозможноеПраво.Имя) <> Неопределено Тогда
			ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Для владельца прав ""%1""
				           |повторно определено право ""%2"".'"),
				ВозможноеПраво.ВладелецПрав,
				ВозможноеПраво.Имя);
			ВызватьИсключение ТекстОшибки;
		КонецЕсли;
		
		Для Каждого ТребуемоеПраво Из ВозможноеПраво.ТребуемыеПрава Цикл
			Если ВозможныеПрава.Найти(ТребуемоеПраво, "Имя") <> Неопределено Тогда
				Продолжить;
			КонецЕсли;
			ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Для права ""%1"" владельца прав ""%2""
				           |указано некорректное имя требуемого права ""%3"".'"),
				ВозможноеПраво.Имя,
				ВозможноеПраво.ВладелецПрав,
				ТребуемоеПраво);
			ВызватьИсключение ТекстОшибки;
		КонецЦикла;
		
		ИндексПрава = ИндексыПравВладельцев[ВозможноеПраво.ВладелецПрав];
		ИндексыПравВладельцев[ВозможноеПраво.ВладелецПрав] = ИндексПрава + 1;
		СвойстваВозможногоПрава = СвойстваВозможногоПрава(ВозможноеПраво, ИндексПрава);
		
		ПраваВладельца.Вставить(ВозможноеПраво.Имя, СвойстваВозможногоПрава);
		МассивПравВладельца.Добавить(СвойстваВозможногоПрава);
	КонецЦикла;
	
	ОбщаяТаблица = Справочники.ИдентификаторыОбъектовМетаданных.ПустаяСсылка();
	ТипыВладельцев.СортироватьПоЗначению();
	
	ПоТипам        = Новый Соответствие;
	ПоТипамСсылок  = Новый Соответствие;
	ПоПолнымИменам = Новый Соответствие;
	
	ОписаниеВерсии = Новый Структура("СвойстваВерсии", Новый Массив);
	ДобавитьЭлементВерсии(ОписаниеВерсии, "Версия", "1");
	
	Для Каждого ЭлементСписка Из ТипыВладельцев Цикл
		СвойстваВладельца = СвойстваВладельцев.Получить(ЭлементСписка.Представление);
		
		// Дополнение отдельных таблиц.
		ОтдельныеПрава = ДополнительныеПараметры.ОтдельныеПраваВладельцев.Получить(ЭлементСписка.Представление);
		Индекс = -1;
		Для Каждого СвойстваПрава Из СвойстваВладельца.МассивПравВладельца Цикл
			Индекс = Индекс + 1;
			Если СвойстваПрава.ИзменениеВТаблицах.Найти(ОбщаяТаблица) <> Неопределено Тогда
				Для Каждого КлючИЗначение Из ОтдельныеТаблицы Цикл
					ОтдельнаяТаблица = КлючИЗначение.Ключ;
					
					Если ОтдельныеПрава.ИзменениеВТаблицах[ОтдельнаяТаблица] = Неопределено
					   И СвойстваПрава.ИзменениеВТаблицах.Найти(ОтдельнаяТаблица) = Неопределено Тогда
					
						Свойства = Новый Структура(СвойстваПрава);
						ИзменениеВТаблицах = Новый Массив(Свойства.ИзменениеВТаблицах);
						ИзменениеВТаблицах.Добавить(ОтдельнаяТаблица);
						Свойства.ИзменениеВТаблицах = Новый ФиксированныйМассив(ИзменениеВТаблицах);
						СвойстваПрава = Новый ФиксированнаяСтруктура(Свойства);
						СвойстваВладельца.МассивПравВладельца[Индекс] = СвойстваПрава;
						СвойстваВладельца.ПраваВладельца[СвойстваПрава.Имя] = СвойстваПрава;
					КонецЕсли;
				КонецЦикла;
			КонецЕсли;
		КонецЦикла;
		
		// Фиксация и добавление строки версии.
		ТипСсылкиВладельца = ТипЗнч(ЭлементСписка.Значение);
		ПраваВладельца = Новый ФиксированноеСоответствие(СвойстваВладельца.ПраваВладельца);
		МассивПравВладельца = Новый ФиксированныйМассив(СвойстваВладельца.МассивПравВладельца);
		ПоПолнымИменам.Вставить(ЭлементСписка.Представление, ПраваВладельца);
		ПоТипамСсылок.Вставить(СвойстваВладельца.ТипСсылки, МассивПравВладельца);
		ПоТипам.Вставить(ТипСсылки,  ПраваВладельца);
		ПоТипам.Вставить(ТипОбъекта, ПраваВладельца);
		
		ОписаниеВерсии.СвойстваВерсии.Добавить("");
		ВладелецПравДобавлен = Ложь;
		ПраваВладельца = ПоТипамСсылок.Получить(ТипСсылкиВладельца);
		Для Каждого СвойстваПрава Из МассивПравВладельца Цикл
			Если Не ВладелецПравДобавлен Тогда
				ДобавитьЭлементВерсии(ОписаниеВерсии, "ВладелецПрав", СвойстваПрава.ВладелецПрав);
				ДобавитьЭлементВерсии(ОписаниеВерсии, "ТипВладельцаПрав", ТипСсылкиВладельца);
				ДобавитьЭлементВерсии(ОписаниеВерсии, "ИерархияВладельцаПрав",
					ИерархическиеТаблицы.Получить(ТипСсылкиВладельца) <> Неопределено);
				ВладелецПравДобавлен = Истина;
				ОписаниеВерсии.СвойстваВерсии.Добавить("");
			КонецЕсли;
			ДобавитьЭлементВерсии(ОписаниеВерсии, "Имя", СвойстваПрава.Имя);
			ДобавитьЭлементВерсии(ОписаниеВерсии, "ИндексПрава", СвойстваПрава.ИндексПрава);
			ДобавитьЭлементВерсии(ОписаниеВерсии, "ЧтениеВТаблицах", СвойстваПрава.ЧтениеВТаблицах);
			ДобавитьЭлементВерсии(ОписаниеВерсии, "ИзменениеВТаблицах", СвойстваПрава.ИзменениеВТаблицах);
			ОписаниеВерсии.СвойстваВерсии.Добавить("");
		КонецЦикла;
	КонецЦикла;
	
	Список = Новый СписокЗначений;
	Для Каждого КлючИЗначение Из ОтдельныеТаблицы Цикл
		Список.Добавить(КлючИЗначение.Ключ);
	КонецЦикла;
	Список.СортироватьПоЗначению();
	ДобавитьЭлементВерсии(ОписаниеВерсии, "ОтдельныеТаблицы", Список.ВыгрузитьЗначения());
	
	СтрокаВерсии = СтрСоединить(ОписаниеВерсии.СвойстваВерсии, Символы.ПС);
	ХешСумма = УправлениеДоступомСлужебный.ХешСуммаДанных(СтрокаВерсии);
	
	ВозможныеПрава = Новый Структура;
	ВозможныеПрава.Вставить("ПоТипам",
		Новый ФиксированноеСоответствие(ПоТипам));
	
	ВозможныеПрава.Вставить("ПоТипамСсылок",
		Новый ФиксированноеСоответствие(ПоТипамСсылок));
	
	ВозможныеПрава.Вставить("ПоПолнымИменам",
		Новый ФиксированноеСоответствие(ПоПолнымИменам));
	
	ВозможныеПрава.Вставить("ТипыВладельцев",
		Новый ФиксированныйМассив(ТипыВладельцев.ВыгрузитьЗначения()));
	
	ВозможныеПрава.Вставить("ОтдельныеТаблицы",
		Новый ФиксированноеСоответствие(ОтдельныеТаблицы));
	
	ВозможныеПрава.Вставить("ИерархическиеТаблицы",
		Новый ФиксированноеСоответствие(ИерархическиеТаблицы));
	
	Возврат Новый ФиксированнаяСтруктура(ВозможныеПрава);
	
КонецФункции

// См. УправлениеДоступомСлужебный.ДобавитьЭлементВерсии
Процедура ДобавитьЭлементВерсии(Контекст, ИмяПоля, Значение)
	УправлениеДоступомСлужебный.ДобавитьЭлементВерсии(Контекст, ИмяПоля, Значение);
КонецПроцедуры

// Возвращаемое значение:
//  ФиксированнаяСтруктура:
//   * ВладелецПрав - Строка
//   * Имя          - Строка
//   * Заголовок    - Строка
//   * Подсказка    - Строка
//   * НачальноеЗначение  - Булево
//   * ТребуемыеПрава     - ФиксированныйМассив из Строка
//   * ЧтениеВТаблицах    - ФиксированныйМассив из Строка
//   * ИзменениеВТаблицах - ФиксированныйМассив из Строка
//
Функция СвойстваВозможногоПрава(ВозможноеПраво, ИндексПрава) Экспорт
	
	СвойстваВозможногоПрава = Новый Структура(
		"ВладелецПрав,
		|Имя,
		|НачальноеЗначение,
		|ТребуемыеПрава,
		|ЧтениеВТаблицах,
		|ИзменениеВТаблицах,
		|ИндексПрава");
	
	ЗаполнитьЗначенияСвойств(СвойстваВозможногоПрава, ВозможноеПраво);
	
	СвойстваВозможногоПрава.ИндексПрава = ИндексПрава;
	
	СвойстваВозможногоПрава.ТребуемыеПрава =
		СортированныйФиксированныйМассив(СвойстваВозможногоПрава.ТребуемыеПрава);
	
	СвойстваВозможногоПрава.ЧтениеВТаблицах =
		СортированныйФиксированныйМассив(СвойстваВозможногоПрава.ЧтениеВТаблицах);
	
	СвойстваВозможногоПрава.ИзменениеВТаблицах =
		СортированныйФиксированныйМассив(СвойстваВозможногоПрава.ИзменениеВТаблицах);
	
	Возврат Новый ФиксированнаяСтруктура(СвойстваВозможногоПрава);
	
КонецФункции

// Для функции СвойстваВозможногоПрава.
Функция СортированныйФиксированныйМассив(ИсходныйМассив)
	
	Список = Новый СписокЗначений;
	Список.ЗагрузитьЗначения(ИсходныйМассив);
	Список.СортироватьПоЗначению();
	
	Возврат Новый ФиксированныйМассив(Список.ВыгрузитьЗначения());
	
КонецФункции


// Возвращаемое значение:
//  Соответствие из КлючИЗначение:
//   * Ключ - Тип
//   * Значение - см. СвойстваВозможногоПрава
//
Функция ПраваВладельца()
	
	Возврат Новый Соответствие();
	
КонецФункции

// Возвращаемое значение:
//   Соответствие из КлючИЗначение:
//     * Ключ - Строка - полное имя права.
//     * Значение - ФиксированнаяСтруктура:
//         * Имя       - Строка - имя возможного права.
//         * Заголовок - Строка - заголовок колонки.
//         * Подсказка - Строка - подсказка колонки.
//
Функция ПредставлениеВозможныхПрав() Экспорт
	
	ВозможныеПрава = ЗаполненныеВозможныеПраваСеанса();
	
	ПредставлениеВозможныхПрав = Новый Соответствие;
	
	Для Каждого ВозможноеПраво Из ВозможныеПрава Цикл
		ПолноеИмяПрава = ВозможноеПраво.ВладелецПрав + "_" + ВозможноеПраво.Имя;
		ПредставлениеВозможныхПрав.Вставить(ПолноеИмяПрава,
			Новый ФиксированнаяСтруктура(Новый Структура("Имя, Заголовок, Подсказка",
				ВозможноеПраво.Имя, ВозможноеПраво.Заголовок, ВозможноеПраво.Подсказка)));
	КонецЦикла;
	
	Возврат Новый ФиксированноеСоответствие(ПредставлениеВозможныхПрав);
	
КонецФункции

// Параметры:
//   ОписаниеВозможногоПрава - см. СвойстваВозможногоПрава
//
// Возвращаемое значение:
//  Структура:
//     * Имя       - Строка
//     * Заголовок - Строка
//     * Подсказка - Строка
//
Функция ПредставлениеВозможногоПрава(ОписаниеВозможногоПрава) Экспорт
	
	ПредставлениеВозможныхПрав = УправлениеДоступомСлужебныйПовтИсп.ПредставлениеВозможныхПрав();
	
	ПолноеИмяПрава = ОписаниеВозможногоПрава.ВладелецПрав + "_" + ОписаниеВозможногоПрава.Имя;
	Представление = ПредставлениеВозможныхПрав.Получить(ПолноеИмяПрава);
	
	Если Не ЗначениеЗаполнено(Представление) Тогда
		Представление = Новый ФиксированнаяСтруктура(	Новый Структура("Имя, Заголовок, Подсказка",
			ОписаниеВозможногоПрава.Имя, ОписаниеВозможногоПрава.Имя, ""));
	КонецЕсли;
	
	Возврат Представление;
	
КонецФункции

Процедура ЗаполнитьИдентификаторы(Свойство, ВозможноеПраво, ЗаголовокОшибки, ОтдельныеТаблицы, ДополнительныеПараметры)
	
	Если ДополнительныеПараметры.ОбщиеПраваВладельцев.Получить(ДополнительныеПараметры.ВладелецПрав) = Неопределено Тогда
		ОбщиеПрава     = Новый Структура("ЧтениеВТаблицах, ИзменениеВТаблицах", "", "");
		ОтдельныеПрава = Новый Структура("ЧтениеВТаблицах, ИзменениеВТаблицах", Новый Соответствие, Новый Соответствие);
		
		ДополнительныеПараметры.ОбщиеПраваВладельцев.Вставить(ДополнительныеПараметры.ВладелецПрав, ОбщиеПрава);
		ДополнительныеПараметры.ОтдельныеПраваВладельцев.Вставить(ДополнительныеПараметры.ВладелецПрав, ОтдельныеПрава);
	Иначе
		ОбщиеПрава     = ДополнительныеПараметры.ОбщиеПраваВладельцев.Получить(ДополнительныеПараметры.ВладелецПрав);
		ОтдельныеПрава = ДополнительныеПараметры.ОтдельныеПраваВладельцев.Получить(ДополнительныеПараметры.ВладелецПрав);
	КонецЕсли;
	
	Массив = Новый Массив;
	
	Для каждого Значение Из ВозможноеПраво[Свойство] Цикл
		
		Если Значение = "*" Тогда
			Если ВозможноеПраво[Свойство].Количество() <> 1 Тогда
				Если Свойство = "ЧтениеВТаблицах" Тогда
					ШаблонОшибки =
						НСтр("ru = 'Для владельца прав ""%1""
						           |для права ""%2"" в таблицах для чтения указан символ ""*"".
						           |В этом случае отдельных таблиц указывать не нужно.'")
				Иначе
					ШаблонОшибки =
						НСтр("ru = 'Для владельца прав ""%1""
						           |для права ""%2"" в таблицах для изменения указан символ ""*"".
						           |В этом случае отдельных таблиц указывать не нужно.'")
				КонецЕсли;
				ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					ШаблонОшибки, ДополнительныеПараметры.ВладелецПрав, ВозможноеПраво.Имя);
				ВызватьИсключение ТекстОшибки;
			КонецЕсли;
			
			Если ЗначениеЗаполнено(ОбщиеПрава[Свойство]) Тогда
				Если Свойство = "ЧтениеВТаблицах" Тогда
					ШаблонОшибки =
						НСтр("ru = 'Для владельца прав ""%1""
						           |для права ""%2"" в таблицах для чтения указан символ ""*"".
						           |Однако символ ""*"" уже указан в таблицах для чтения для права ""%3"".'")
				Иначе
					ШаблонОшибки =
						НСтр("ru = 'Для владельца прав ""%1""
						           |для права ""%2"" в таблицах для изменения указан символ ""*"".
						           |Однако символ ""*"" уже указан в таблицах для изменения для права ""%3"".'")
				КонецЕсли;
				ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОшибки,
					ДополнительныеПараметры.ВладелецПрав, ВозможноеПраво.Имя, ОбщиеПрава[Свойство]);
				ВызватьИсключение ТекстОшибки;
			Иначе
				ОбщиеПрава[Свойство] = ВозможноеПраво.Имя;
			КонецЕсли;
			
			ТипПустойСсылки = Новый ОписаниеТипов("СправочникСсылка.ИдентификаторыОбъектовМетаданных");
			Массив.Добавить(ТипПустойСсылки.ПривестиЗначение(Неопределено));
			
		ИначеЕсли Свойство = "ЧтениеВТаблицах" Тогда
			ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Для владельца прав ""%1""
				           |для права ""%2"" указана конкретная таблица для чтения ""%3"".
				           |Однако это не имеет смысла, т.к. право %4 может зависеть только от права %4.
				           |Имеет смысл использовать только символ ""*"".'"),
				ДополнительныеПараметры.ВладелецПрав,
				ВозможноеПраво.Имя,
				Значение,
				"Чтение");
			ВызватьИсключение ТекстОшибки;
			
		ИначеЕсли ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(Значение) = Неопределено Тогда
			Если Свойство = "ЧтениеВТаблицах" Тогда
				ШаблонОшибки = НСтр("ru = 'Для владельца прав ""%1""
				                          |для права ""%2"" не найдена таблица для чтения ""%3"".'")
			Иначе
				ШаблонОшибки = НСтр("ru = 'Для владельца прав ""%1""
				                          |для права ""%2"" не найдена таблица для изменения ""%3"".'")
			КонецЕсли;
			ТекстОшибки = ЗаголовокОшибки + СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонОшибки,
				ДополнительныеПараметры.ВладелецПрав, ВозможноеПраво.Имя, Значение);
			ВызватьИсключение ТекстОшибки;
		Иначе
			ИдентификаторТаблицы = ОбщегоНазначения.ИдентификаторОбъектаМетаданных(Значение);
			Массив.Добавить(ИдентификаторТаблицы);
			
			ОтдельныеТаблицы.Вставить(ИдентификаторТаблицы, Значение);
			ОтдельныеПрава[Свойство].Вставить(ИдентификаторТаблицы, ВозможноеПраво.Имя);
		КонецЕсли;
		
	КонецЦикла;
	
	ВозможноеПраво[Свойство] = Массив;
	
КонецПроцедуры

Функция ИерархическийОбъектМетаданных(ОписаниеОбъектаМетаданных)
	
	Если ТипЗнч(ОписаниеОбъектаМетаданных) = Тип("Строка") Тогда
		ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ОписаниеОбъектаМетаданных);
	ИначеЕсли ТипЗнч(ОписаниеОбъектаМетаданных) = Тип("Тип") Тогда
		ОбъектМетаданных = Метаданные.НайтиПоТипу(ОписаниеОбъектаМетаданных);
	Иначе
		ОбъектМетаданных = ОписаниеОбъектаМетаданных;
	КонецЕсли;
	
	Если ТипЗнч(ОбъектМетаданных) <> Тип("ОбъектМетаданных") Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Если НЕ Метаданные.Справочники.Содержит(ОбъектМетаданных)
	   И НЕ Метаданные.ПланыВидовХарактеристик.Содержит(ОбъектМетаданных) Тогда
		
		Возврат Ложь;
	КонецЕсли;
	
	Возврат ОбъектМетаданных.Иерархический;
	
КонецФункции

#КонецОбласти

#КонецЕсли
